{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b6399d63",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torch.nn import functional as F\n",
    "\n",
    "from torchvision import datasets\n",
    "from torchvision import transforms\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "from matplotlib import gridspec\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "import os\n",
    "os.environ[\"KMP_DUPLICATE_LIB_OK\"]=\"TRUE\"\n",
    "\n",
    "from IPython import display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d9eb0c00",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 判断是否有GPU\n",
    "\n",
    "device = \"cuda:0\" if torch.cuda.is_available() else \"cpu\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3adb1aca",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    加载数据\n",
    "    - 模仿的对象\n",
    "    - 真品\n",
    "\"\"\"\n",
    "\n",
    "# 加载并预处理图像\n",
    "data = datasets.MNIST(root=\"data\", \n",
    "                      train=True, \n",
    "                      transform = transforms.Compose(transforms=[transforms.ToTensor(),\n",
    "                                                                transforms.Normalize(mean=[0.5], std=[0.5])]),\n",
    "                      download=True)\n",
    "\n",
    "# 封装成 DataLoader\n",
    "data_loader = DataLoader(dataset=data, batch_size=100, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f0662964",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义生成器\n",
    "\"\"\"\n",
    "\n",
    "class Generator(nn.Module):\n",
    "    \"\"\"\n",
    "        定义一个图像生成\n",
    "        输入：一个向量\n",
    "        输出：一个向量（代表图像）\n",
    "    \"\"\"\n",
    "    def __init__(self, in_features=100, out_features=28 * 28):\n",
    "        \"\"\"\n",
    "            挂载超参数\n",
    "        \"\"\"\n",
    "        # 先初始化父类，再初始化子类\n",
    "        super(Generator, self).__init__()\n",
    "        self.in_features = in_features\n",
    "        self.out_features = out_features\n",
    "        \n",
    "        # 第一个隐藏层\n",
    "        self.hidden0 = nn.Linear(in_features=self.in_features, out_features=256)\n",
    "        \n",
    "        # 第二个隐藏层\n",
    "        self.hidden1 = nn.Linear(in_features=256, out_features=512)\n",
    "        \n",
    "        # 第三个隐藏层\n",
    "        self.hidden2 = nn.Linear(in_features=512, out_features=self.out_features)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \n",
    "        # 第一层 [b, 100] --> [b, 256]\n",
    "        h = self.hidden0(x)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        \n",
    "        # 第二层 [b, 256] --> [b, 512]\n",
    "        h = self.hidden1(h)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        \n",
    "        # 第三层 [b, 512] --> [b, 28 * 28]\n",
    "        h = self.hidden2(h)\n",
    "        \n",
    "        # 压缩数据的变化范围\n",
    "        o = torch.tanh(h)\n",
    "        \n",
    "        return o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "9550e835",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义一个鉴别器\n",
    "\"\"\"\n",
    "\n",
    "class Discriminator(nn.Module):\n",
    "    \"\"\"\n",
    "        本质：二分类分类器\n",
    "        输入：一个对象\n",
    "        输出：真品还是赝品\n",
    "    \"\"\"\n",
    "    def __init__(self, in_features=28*28, out_features=1):\n",
    "        super(Discriminator, self).__init__()\n",
    "        \n",
    "        self.in_features=in_features\n",
    "        self.out_features=out_features\n",
    "        \n",
    "        # 第一个隐藏层\n",
    "        self.hidden0= nn.Linear(in_features=self.in_features, out_features=512)\n",
    "        \n",
    "        # 第二个隐藏层\n",
    "        self.hidden1= nn.Linear(in_features=512, out_features=256)\n",
    "        \n",
    "        # 第三个隐藏层\n",
    "        self.hidden2= nn.Linear(in_features=256, out_features=32)\n",
    "        \n",
    "        # 第四个隐藏层\n",
    "        self.hidden3= nn.Linear(in_features=32, out_features=self.out_features)\n",
    "        \n",
    "    \n",
    "    def forward(self, x):\n",
    "        \n",
    "        # 第一层\n",
    "        h = self.hidden0(x)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        h = F.dropout(input=h, p=0.2)\n",
    "        \n",
    "        # 第二层\n",
    "        h = self.hidden1(h)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        h = F.dropout(input=h, p=0.2)\n",
    "        \n",
    "        # 第三层\n",
    "        h = self.hidden2(h)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        h = F.dropout(input=h, p=0.2)\n",
    "        \n",
    "        # 第四层\n",
    "        h = self.hidden3(h)\n",
    "        \n",
    "        # 输出概率\n",
    "        o = torch.sigmoid(h)\n",
    "        \n",
    "        return o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "f9acef33",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Discriminator(\n",
       "  (hidden0): Linear(in_features=784, out_features=512, bias=True)\n",
       "  (hidden1): Linear(in_features=512, out_features=256, bias=True)\n",
       "  (hidden2): Linear(in_features=256, out_features=32, bias=True)\n",
       "  (hidden3): Linear(in_features=32, out_features=1, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"\"\"\n",
    "    构建模型\n",
    "\"\"\"\n",
    "# 定义一个生成器\n",
    "generator = Generator(in_features=100, out_features=784)\n",
    "generator.to(device=device)\n",
    "\n",
    "# 定义一个鉴别器\n",
    "discriminator = Discriminator(in_features=784, out_features=1)\n",
    "discriminator.to(device=device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "88cb9255",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义优化器\n",
    "\"\"\"\n",
    "\n",
    "# 定义一个生成器的优化器\n",
    "g_optimizer = torch.optim.Adam(params=generator.parameters(), lr=1e-4)\n",
    "\n",
    "# 定义一个鉴别的优化器\n",
    "d_optimizer = torch.optim.Adam(params=discriminator.parameters(), lr=1e-4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "1886dd52",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义一个损失函数\n",
    "\"\"\"\n",
    "loss_fn = nn.BCELoss()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "361ea6e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义训练轮次\n",
    "num_epochs = 1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "5b7af8d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    获取数据的标签\n",
    "\"\"\"\n",
    "\n",
    "def get_real_data_labels(size):\n",
    "    \"\"\"\n",
    "        获取真实数据的标签\n",
    "    \"\"\"\n",
    "    labels = torch.ones(size, 1, device=device)\n",
    "    \n",
    "    return labels\n",
    "\n",
    "def get_fake_data_labels(size):\n",
    "    \"\"\"\n",
    "        获取虚假数据的标签\n",
    "    \"\"\"\n",
    "    labels = torch.zeros(size, 1, device=device)\n",
    "    \n",
    "    return labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "c8592d6c",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    噪声生成器\n",
    "\"\"\"\n",
    "def get_noise(size):\n",
    "    \"\"\"\n",
    "        给生成器准备数据\n",
    "        - 100维度的向量\n",
    "    \"\"\"\n",
    "    X = torch.randn(size, 100, device=device)\n",
    "    \n",
    "    return X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "0674b255",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取一批测试数据\n",
    "\n",
    "num_test_samples = 16\n",
    "test_noise = get_noise(num_test_samples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "0264a778",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([16, 100])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_noise.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "d0c8c082",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnwAAAHICAYAAADUXjeoAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deXxW1ZnA8RO2EEggQCAgiAFEcakoUgXHVkvrUqt1qS1ad9y1fqp1xqX6UafWuqIyY6UO1c4oVot2tGpdp0pVHFRAcQqCIIR9SdgSQgIEMn/0k6fPOb73ct83977Lye/71/N6znvfG3Lem+N9nntOUUtLiwEAAIC/OuT6BAAAAJAsJnwAAACeY8IHAADgOSZ8AAAAnmPCBwAA4DkmfAAAAJ5jwgcAAOA5JnwAAACeY8IHAADguU7pdK6oqGipqqpK6FQQpLq62tTW1hbl+jwKVdLjdt26dRJXVlYm9jmFaPbs2bUtLS19c30ehYprbnR616iiomiXS3enKf0+xm7bMHZzI2y+kNaEr6qqysyaNSues0ph9+7dEnfowM3HVqNHj871KRS0pMftww8/LPG1114b67HD/iCF9Y36By9pRUVFy3J9DoUsH6+5u3btsl537NgxZb90xm4cduzYIXGXLl0ivWfnzp3W686dO0vM2G2bpMdue6e/u8b84/sbNl9gVgUAAOC5tO7whYnj7gJ39ZBtcdxVjvuunpbOdylf7uohGUH/R5/Kxo0bJe7du3dgP30MfYfMmK/c7ZI46I6eK9vjMepdPa1TJ/tP4McffxzX6UDJ9t3e9iCTv1fMsAAAADzHhA8AAMBzTPgAAAA8F1sNHzl5FCLqRlEo0hmrYXV7QdwaOF0zGPX6nmlNbNxLqkTlvufrX/962sfAnjE/yA/8tQMAAPAcEz4AAADPxZbS9ZWbNgjCLWsUirD0WT4u3oz0Bf0eo17PjAlOye5hseLIx89EJosrsyQI8Hfc4QMAAPAcEz4AAADPMeEDAADwXLup4XPrOHQdit6GyBhj/vu//1vi+++/X+Ivv/zS6seSHsgn27dvl/juu++W+IILLrD69ezZM2VsjL1tFvV8+cW9hunXu3btstp0XZ3m1t/FsR1Z1HES1i/q+NLnG7U2j7HrhzVr1livBwwYkKMzyUxzc7PE7ncoW5ixAAAAeI4JHwAAgOfyNqUbdrtet+mV3Y2xU1JhDjjgAImXLFkS2E9/bkNDg9VWWlqash/ar2wuAVFdXW29PuSQQySur6+X+IEHHrD6fe1rX5P4/fffDzw+Yzq/hKVBo5aXuKle9/qp6WOG7bqh08lz586VeMSIEVa/kpKSSOcYVabp4zBh/x7ILTeFm+muLkmqq6uTWKdwjTHmnnvukfjee++12rJ1rc2PfyUAAAAkhgkfAACA5/I2pRt2i1O3RU3h6idvjTFmxYoVaZ/TF198Yb3WKbSgp+LQvsS98bubYtJP4k6bNs1q27p1a8pjuKUIn3/+eeB5wG/pPB2rx0ZYGc369eslrqiokPiXv/yl1e+nP/2pxH379g08D50iXr16tdVv7733jnTuSaR7kX1hv6uwNG7Q+9yxq9viGAvPP/+8xA899JDV9tJLL8X6WZngDh8AAIDnmPABAAB4jgkfAACA5/K2hi/u5S2+853vWK8nTZok8VVXXRX4Pr2UgLtKPfVPiEtQzYlbp9K1a1eJf/7znwceQ3O/O3rpALcGlvqm9ssdPzt27EjZb86cOdZrff38+OOPJb799tutfro2z6031TtoFBcXS9y7d2+rXxxjMuwY+bK8B/4ujppoPe7mz59v9evTp4/Ee+21V6TPamxstF5v3rxZYl23qv+7McacfvrpEn/66aeRPitujG4AAADPMeEDAADwXF6ldJNMJ+ldMYwx5ic/+YnE+lF/Y+x0g74F7Ka/oi4JA7jc8R21PODLL7+U+MEHH7Ta9LIXvXr1kthNzV166aWRzwvth/u712lWncY69NBDrX7HHnusxHqDe3fpldraWond1NoxxxyT8pzKysr2cNZ7ls3db5A9usTK/Vt83nnnSVxVVSWxe+3TKd2w+YdezkWX1RhjzF133SXxiy++KPHbb79t9ZswYcJXf4gs4w4fAACA55jwAQAAeI4JHwAAgOfyqoZP583jrrtwc/y6huT444+32nRtQPfu3SV2c/fU8CEuUce3rke55ZZbAvvV19dLfO2111pt9957b9qfi/yT9BI6+ph660i3JvTOO++UWC9r4l4fr7/+eomnT59utelrq65T1Uu0pCNoWzhjkv07g7YLGtfu76pTp39MX9auXWu1PfnkkxLX1NRIXFlZmdE56XHtftajjz4q8W9+8xuJ77jjDqtfJvWo7lZwbV02iDt8AAAAnmPCBwAA4Lm8Sulqcd9ad28H62UGNm3aZLW99957ErvLuQQdk1QAkuCO2xkzZkjc0NBgtekx+Oabb0qsl83IlF6t3hjKGfJBc3OzxDrlmgQ9trp16xZ4Hjp9dvjhh1v91q9fL/GQIUOstptvvlniOMaWPt9t27ZZbTolvXTpUqtt1KhRbf5stE3Q39KwpawqKiqstqamJond5YEyocfQF198EXheemmsW2+9tc2fG0Z/74yxU9xBuMMHAADgOSZ8AAAAnsvblG7c1q1bZ73+3ve+J7F7K3Tw4MES69u1bgrNTW2gsOXLE3t1dXUS690OjImenh0zZkxgWyY/Fync/JN0Gld/H/Q10k3v6/TZ0UcfLfFJJ51k9XviiSckdlOpAwcOTPlZcdArLbiv9Y40KFzumIm6c1FU5eXlErupVP1Zt912W+A5ZHLdDXsqN5PvCXf4AAAAPMeEDwAAwHNM+AAAADyXlRq+fFi+xF3ZXe9YcMEFF1htCxYskHjEiBESu/Uecf8sLH2RW+7vU69y3tYVztOxfft2icNq8dwajrPOOitlW9LfuXypfWzP3Loi/Tpst4qw35Vu08fTS1oZY8zcuXMlXrlypcS///3vA489YcIE67W721GS9Hh1r7lx1w8ifXrZHF3DrGubjTGmR48eEuvdsYyx61szuR6540LX62/ZssVqu+iiiyTesGGDxD179kz7c/dEL23Ur1+/tN/PHT4AAADPMeEDAADwXFbuX2czxaM3jde7ZPz4xz8OfI+7cvaqVaskdpfFQPuRzTTugw8+KPGUKVMkXrhwYeB73NXl9bIXSS/ZgewLS527qcg4UpP683RcW1tr9TvmmGMk1mUQ+++/v9Vv3rx5Ej/22GNWWxx/I4JKh9L5d0PuBf3NdceILjPQaWBX1PIWfTx3TqDTuJWVlVbbpEmTJA4rnwgTtewtkzSuxh0+AAAAzzHhAwAA8Fxs97P17dBc3iYvKSmRuKysTGL3tr5O1w0YMMBqy1U6jKdy269PP/1UYv2UeBg3jZGrcctTudnh/jsvWbJEYr3qgDHxlCPoz9OlMp999pnVT6dxNZ3CNcbercB9Txx/M+IYh2GpQWSf/rvdtWtXq02PITcNrJ/a3bhxo8Tuk7P6fePGjZP4vffeCzynmpoa6/XWrVtTnpM7pvX4dMdq0NiNewUE7vABAAB4jgkfAACA55jwAQAAeC62Yrtc1e25tSB33XWXxDfddJPE9913n9VP16S8+uqrgcfPh11C4J9FixZZr6dOnZr2MdwaKcZq+zJkyBCJk/h96/Gkdxm6++67Mzre6tWrJQ6q+3M/N9u737AMV/5ya9z1ji/ueHrjjTck3rZtm8T/8z//Y/XTc4Swuj3tmmuusV7feOONEl9xxRUSH3nkkVa/sPHq1uolhTt8AAAAnmPCBwAA4Lms52HjTju5t3L15sL68Wl9W9cYe8kWd+XssFXa0T7pTbF79+5ttWUyjg844ADrddRdAvQuB+4SA6Rx/eZe66KmNJuamiR2l7aIavny5RLPnj07sF/Y0lL6s8NSulF3yXCPEfQ+t58+R74z+U3verXXXntZbXrpFfdaeMopp0i8fft2iS+99FKr33PPPRfpPHR69v7777fa9HjSy9O534WwuUTUZVnaijt8AAAAnmPCBwAA4DkmfAAAAJ7Leg1fWM2Ezle7W9zoR7Dr6uok3nvvva1+P/7xjyWePHmyxO6yLLfddpvE1dXVVtu+++6b8pwyrfdguYzC16dPn0j9wuqKLrzwQon1FoDG2Nvz6CWO/vSnP1n99Pcg7JwYt/7JdBmSTOv29O9cH0PXKbn0+Ne1g65Ml6jQ49/9uYLGaC63+kT69BgaNGiQxLt27bL69ejRI/AYxcXFEustJ91a/pdfflniM844Q2K3XvDZZ5+VOGzLNH3uYXWqUcd/3Ndd7vABAAB4jgkfAACA5/LqXnfYI/elpaUSf/rppxIPGDDA6jdz5kyJH3zwQYn/9re/Wf10Kvjpp5+22q6++mqJ3SU4MkE6rPCFrfCvb8G76ShdmvDUU09JHDYmdMpg5MiRVlv37t0jnW8cY45x276EpVIPO+wwid1xod8X95IneukNY+xUXVhaLOrSLm7pEDtt5F7Q79X971HHV9i1W5cIhP13neIN+9yo5RNhYzLJ6y53+AAAADzHhA8AAMBzOd1pI6xN37o3xn7i6+ijj5ZYb+ptjL3Thr49/61vfcvq9+KLL0r84YcfWm3Lli2TWK/gHbaKPPy2cuVKiQcPHhzYzy1FmD59usT6aTE3laTH1tq1ayV2n0QLe/JLH1N/VtKp2bD0BHIj6Dob9rtx2/TTuHrXorDf96GHHhrps1xBO2O4x4j6dKP+LrhpWt2PFG5+C0vHRqWvre5qHSeccILEffv2lfiDDz6w+sU9TnJ1jeQOHwAAgOeY8AEAAHiOCR8AAIDnsl7DF5aT1ytpuznuM888U2Jdn3Tuueda/fQuHBUVFRK7q8Pvt99+EuudNdzPzrRuIAj1ToVJLw/h/g716u3PPfec1XbRRRdFOn7//v0lDqsXCRuPSdYj5WoZAWQmbFmSIG6/adOmSTx+/HiJ3333XavfqlWrJNb1remMC/13QS+Joa/1xnx1twVNfzd0Dbi7tIt7TOSvTGv4dA2nHodXXnml1W/FihUS63ESVqddyLjDBwAA4DkmfAAAAJ7Leko3bGkTfevVvQ3/zDPPSKyXZZk4caLVT6fX9C1g93P1reJsLrdC+qswVVVVSeymvvT4cXdt0ekjPabdHTMmT54scaab3SeJcZvfkki5n3baaRK/8cYbEuvyGmPsHWSGDBnS5s/VO824x9Bt27dvD2zT/x6kcAuX/p2mQ5e3bNmyRWJ3mathw4ZJvGHDBol9vd5xhw8AAMBzTPgAAAA8x4QPAADAc1mv4QsTVku3ZMkSiXVef+nSpVa/4447LuX73RqXOLZsgd/0EhB6/LjjRY/bRYsWBR5Dc49xyimnZHyeucZSQ7nn/psHbU8W9rtxl67SdVBTpkyReOvWrVY/Peb1VlXpXFf1eek67G7duln9om6LlukYdL+/yL6w33+QsL/vum7PvR7rMdQerlvMdAAAADzHhA8AAMBzeZXS1bdU3fSuTiOceOKJEgelcPckk6VYSF21L0FjxE0L6HHgpmYfffTRlMd477332nh20SU9bvkeZEfYjhnu7yAonRp2DJ0GM8Ye/1OnTpVYX3+NMWbQoEESv/jiixK71+awz9ZpvPLycok/+ugjq9+YMWMCj6H/RpSWlgb2CzN06NCM3of4BKVx3fGpx7jbpr8P77zzjsQjR460+vXq1UtiPT7juKZt2rQp8LPc89VLduldYuLGHT4AAADPMeEDAADwXF6ldMOenD3yyCNTxlGl83SafgpY32plxfb2JegWv5uaqq2tlfjhhx+22h566CGJ9Zh2d5KJ+6lxvXl42NOMKBxh17CwdFfYMfRYDkslTZgwQeK6ujqrTa+U8Oqrr6Y89p7oFKx+X1gK1z1+pmlcLZu7LqFtwv4267Exbtw4idetW2f1a2pqkjjqE8FuSY/+ri1evFji4cOHBx7D/X4mmca1PjcrnwIAAICcYcIHAADgOSZ8AAAAnkukhu+kk06yXuu6jjC52vFC1+wZY+f/qdtrP9z6naBdMtzx0q9fP4mjjuEkajYaGxslLikpif34QViuKDvC6vTcujq9tEncy03onQuMMeb1119v8zFXrVol8cCBAyO9h3Hmh6jXXffaGvVaq8d/3759MzqG5p6vvtbq5YXy8brIHT4AAADPMeEDAADwXCIp3agp3HyVD7dekX1BqQRjwtNiuSpFcEVN48aR4ot7GRnsWdi/s07husJ+x5n8/pNIVUVN44aNu6jjOuoxkB1h191MBf2Ok/jbrktp8h1XagAAAM8x4QMAAPAcEz4AAADP5dXWakC+8qmuM466Ler28lvcS7Hki7BxF/XnjOMYyG9skZcaV20AAADPMeEDAADwXFE6j6EXFRXVGGOWJXc6CLBPS0tL3z13QyqM25xi7LYBYzenGLttwNjNmcBxm9aEDwAAAIWHlC4AAIDnmPABAAB4jgkfAACA55jwAQAAeI4JHwAAgOeY8AEAAHiOCR8AAIDnmPABAAB4jgkfAACA55jwAQAAeI4JHwAAgOeY8AEAAHiOCR8AAIDnmPABAAB4jgkfAACA55jwAQAAeI4JHwAAgOc6pdO5oqKipaqqKqFTQZDq6mpTW1tblOvzKFSM29yZPXt2bUtLS99cn0ehYuzmDmO3bRi7yWppabFeFxX9fYoQNl9Ia8JXVVVlZs2alen5IUOjR4/O9SkUNMZt7hQVFS3L9TkUMsZusnbt2mW97tixo8SM3baJe+wGTXDSeV/U98Rh9+7d1usOHdJPqIb9zM3NzVZbp05/n86FzRfSmvABAOALPcFDbkSdyGU6WYtjkqcnV60Tqz3JZILnCjv3TI5PDR8AAIDnmPABAAB4jgkfAACA56jhAwAAOZHNBynCTJw4UeLrr7/easvHWk9q+AAAAPAVTPgAAAA8R0oXAAC0a24aV8tV2nnp0qXW6yFDhgT2dZe3SYU7fAAAAJ5jwgcAAOA5JnwAAACea7c1fDt37pR49erVVlvPnj0lfuONNyQeP3588icGhIhSp2FM/ix1AESh9x3V21h17tzZ6se4Rltkuh9vroTV7Lmi/Czc4QMAAPAcEz4AAADPtduU7rx58yQ+7LDDAvuVlJRITEoXuVZXVyfx5ZdfbrX99re/lbi0tDRr54TCpVNc2Uxvvfvuu9brs88+W+J+/fpJPGfOnKydE7In6XGnSwT0jhTuZ+3atUtiXeZVXFxs9cv31K8xxjQ1NRljwst+uMMHAADgOSZ8AAAAnmu3Kd3vfve7ab/n0ksvtV5PmTIlrtMBUnJvz3/jG9+Q+KKLLrLaXnnlFYnPOuusZE8MXkgyVeWO3W3btkl86623Wm1r1qxJGT/88MNWv2uvvVbiQkizITX9u8v0ydlnnnlGYvd6F5TSdT+roaFB4rKyMom3b99u9evUqVPKOJ907drVGBP+78cdPgAAAM8x4QMAAPAcEz4AAADP5WcyOgtuu+02ia+66qrAfrNmzZL4wAMPTPScANekSZOs13pXmJ/97GdW2w033CAxNXyIk6590stXGGPXNIXVS23atEni9957L/CzBg8eLHFlZaXVppfRyNdaKqQn01pMvUzajh07rLYuXbqkfM/mzZut13vttZfE69evl/iTTz6x+nXs2FHisWPHWm16zOe7wjlTAAAAZIQJHwAAgOfazT3xrVu3Wq/D0rj6FjNpXGSbToXpkgJjjNmwYYPEFRUVVtudd96Z7Imh3WpubpZYL5tijJ2C1dxU1z333CNxnz59rLb6+nqJq6urJWbplcLWei0L+z3qJVSMCU6Rhi3f4qb3dYq3c+fOEvfs2dPq9/jjj0v80EMPSfyLX/zC6qd33tDj0xhjysvLU55H0mPXXTpG/5xBuMMHAADgOSZ8AAAAnmPCBwAA4Ll2U8N30003Re7r1goA2aRrPy677DKr7dlnn5XYXXrg008/lfiII45I6OzQHunapH322SejY5xxxhkSP/roo1abHvO6pksvh4HCE6WOLdNlTfSxN27caLXpbdL0MkLuNVOPyUceeUTi66+/3ur36quvSuyOXd2ml9EaM2ZM+A/QRrquMCru8AEAAHiOCR8AAIDn2k1K99e//nXkvqR0kS8mTpxovdZj87jjjrPaSOMiKZksMeEut3HCCSdI7F5jP/vsM4njTuNGXfYDyWlqarJed+3aNe1juGNQjyGdwjXGXqJE93OPoV/rnYsWLFhg9dM7b9TV1VltAwYMkHjVqlUpPzfVZ7fVkiVLrNdDhw7d43sY+QAAAJ5jwgcAAOA5r1O6/fv3z/UpAG2ybNky67VOT0W5hQ9kk05j7dq1y2rTu3W46S29iX3cSOHmXiYp3HRMnTrVen3sscdKPGTIEIndNKv71G4rvRqCMcbMmzdP4unTp1ttPXr0kHjatGkS690+jMnsqdowmVz/+SYAAAB4jgkfAACA55jwAQAAeM7rGr4NGzZE6qdrS3JJrwhujP1oOdqnTZs2Wa/1jgc//elPs306KdXW1lqvKyoqcnQmaBW2FEW2PPbYY4FtI0eOtF737t076dNJ6aOPPrJes7RR/lq5cqX1ul+/fhL/8pe/tNqGDRsmsV42ZfPmzVa/vn37Shy2m4yuR3XnC1u2bJF40aJFEh900EEpfor0xL20C3f4AAAAPMeEDwAAwHPepXQbGxsljpqqzZcNuknhwhh73C5fvjyw3/z5863XY8eOTeycwpDCzT/ZTOPqnQd0Ks3d0F578803Ez2nqEjhFg536Z6FCxdKvHXrVqvtjDPOkHjSpEkS77///la/Dz74QOIf/vCHEl955ZVWP11u5S7zo1PG7o4iQdwli7Qk5yPc4QMAAPAcEz4AAADPeZfSraqqyvUpoIDo9Kl+SiuXSkpKAtt0qo6dZJAP/va3v0nsPrEdZMaMGdbr0047LdZzQn7r3r27xA0NDZHe45Zo1dTUSPznP//Zajv66KMl/sUvfhF4TL2DxuWXXy6xu2KG5j45q/vq9O727dutfro8Z/jw4YHH19zSjLY+fc8dPgAAAM8x4QMAAPAcEz4AAADP5UfRUozWr18fqd+4ceMSPhMUgnyp29MuvfRSiSdPnmy16RoO6lWRD84///xI/XTNEcuhtG9R6/Y0d9kyvRvGhAkTrLbi4mKJt23bJrFbm6d3ydBLsfzHf/xH4Hno+kNj7CVh9A4ys2bNCvysTLHTBgAAAEIx4QMAAPBc/uWzsuQvf/lLrk8BELt375b4ySefDOxXVlYmcTZ3UwBauamppUuXRnqf3oWgS5cusZ4T/Ode71566SWJ33rrLavtmmuukVgvtzJixAirny7pmTp1qsTukldr166VuFu3blbbwIEDJdZpYXeJolGjRknsLu2iX+udPNx++t8grC0Id/gAAAA8x4QPAADAc0z4AAAAPOddDV9Qjru+vj4XpwNEous29JIF7lIE7nY9QLb16NHDeq2Xx9D1fFOmTLH66eUrevfundDZob3Q9XKrVq2y2u6++26Jdc1d2DJc1113ncRvv/221aZr/t2l38aMGSPxU089JfHFF19s9Quq0zMmuP4urC6PrdUAAADwFUz4AAAAPFfwKV13hW33UeVW7urYQD7RaQJ9q37Xrl1WP720BZAtehzOmTPHagtalkXvdmCMMb169Yr/xNBu6fRsZWWl1eaWwkShr7sPPfSQ1TZp0iSJH330Uauta9euEr/22msSu2nbTGSy9EoY7vABAAB4jgkfAACA5wo+pfu73/0usE3f8mVXAuSznj17StyxY0eJ77vvPqtf2FNmQFJ0eurII48M7Kevs+edd16i5wS0Ctu5JajMK8zGjRut1zqN6x7vuOOOk3j16tUS77vvvla/THbJiHvewh0+AAAAzzHhAwAA8BwTPgAAAM8VTEGQznlv27Yt0nuGDh2a1OkAsbr11lsl1ksKfP7551Y/alGRLn3tTGf86Pc1Njam/O+uPn36pHl28Nnu3buNMfEsUZKpTK6ZRx11lPU67Dv0jW98Q2I95wj73J07d1qvw2oQ48QdPgAAAM8x4QMAAPBcwaR09e3R0tLSSO95//33kzodoE3ctNhzzz0n8fHHHy+xXuEdyESmZQD6fYcddpjEbnpOj+V169Zl9FnwU5RUbty7SWTbFVdcIfE777wT6T3ZSuG6uMMHAADgOSZ8AAAAnmPCBwAA4LmCqeHT9LIV7uPNs2bNkrhv375ZOycgHW7dyoIFCyTu2rWrxLt27craOcEfzc3NEme6HV/rkhrGGFNSUiKxO3bHjh0rcS6X30BhyseaPT32Xfr6bIwxgwcPTtkvidpE/fdAb8EZFd9OAAAAzzHhAwAA8FzBpHT17VF9u9W99TpjxoysnROQKTf1tWXLFomLi4slzuS2fVtkuisD8ksmaVw3BfXuu+9KPHfuXIm7d+9u9Rs4cGDan5XpOYWNScYu4uJen/U845BDDrHaxowZk/IY+ppujDE9e/aUONPx2da/B9zhAwAA8BwTPgAAAM8VTEpX3wLVT6C5zjnnHImXLVuW6DkBcVm/fr3ElZWVOTsPUmHtl/u7P+aYYyTWqyHoDeKNMeaFF16I9TyWL18ucdATkKkwdgtTfX299bqsrCwn56FLAu655x6r7YYbbpD4ww8/tNpeeeWVlMcrLy+P8eziwR0+AAAAzzHhAwAA8BwTPgAAAM8lUsPX1NRkvXZXpk4SdXvIlLurRTaXRPna176Wtc+Cf9xlWMLqnKPSNXH6+LrGLi5r1qyROJ26PRS+sJq9OHaMCaPr9nQt4amnnmr1+/zzzyV+/vnnrbZevXqlPLa7C5g+/1zVm3KHDwAAwHNM+AAAADyXSEo3mylcIC7Z3tUCiEscKdxcGjBgQNY+ix05CkcSaVxN//51arm0tNTq9/jjj0s8ZcoUqy3o70bnzp0zOqckxyd3+AAAADzHhA8AAMBzTPgAAAA8VzBbqwHZlg+1PvoccnkegC/4DmVfIVzHws5Jt3XokOx9siT/bbjDBwAA4DkmfAAAAJ4rcm+1hnYuKqoxxrCVRfbt09LS0jfXJ1GoGLc5xd/0l+0AACAASURBVNhtA8ZuTjF224CxmzOB4zatCR8AAAAKDyldAAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPMeEDAADwHBM+AAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPMeEDAADwHBM+AAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPdUqnc0VFRUtVVVVCp4Ig1dXVpra2tijX51Go4h63zc3N1uuOHTtKXFQU7dfkHqNTp398FVtaWgLfF3b8oPdt3LjRet2nT59I56U/q0MH+/8No/6cs2fPrm1paekbqTO+gmtu7jB224axmxth84W0JnxVVVVm1qxZ8ZwVIhs9enSuT6GgVVVVmY8//jhl2+7duyV2JzVBNm3aZL0uLS2VuHPnzlZb0CTMPUbv3r0l3rVrV+Bnh00M9ft029NPP231u/DCCwOPX1NTI7H+WfTPaIz9b+Weh27r0KHDssAPwx5xzc2doqIixm4bMHZzI2y+QEoXAADAc2nd4QMKnXtnrVevXhLru31h73NTovrOWtRUbc+ePQM/S6eI3ePt3Lkz5bHd92nnnXee9TosZax/Np22dc9Da2pqCmwDgHTo61PU0hFEwx0+AAAAzzHhAwAA8BwTPgAAAM9Rw4d2pVu3btZrXS8SVANnjDHl5eWBbWHva2xslLikpERi94lgfR7V1dUSDxkyxOq3ZcsWid0nZ4POw62DaWhoCHxP165dU567ewxdP6h/LmPCayEBIAx1e8nhDh8AAIDnmPABAAB4jpQu2oXWlGlYutFtC0rHrly50uo3cODAwGPqFKlOx+q0rTHGHHLIIRLr1endcyorK5N46dKlVtugQYMk1osmuws56/Rxly5dAtv0ubtLr+h+O3bssNpYpgVJYckOFAr32r1582aJ9UL72cQdPgAAAM8x4QMAAPAcEz4AAADPtdsavnfeeUfijz/+2GobP368xFOnTpX4lltuSf7EkIjWeh93CZGtW7dK7C5zouvgdL1QRUWF1U/Xarh1Rbp+Ttff6Xo7t5+uHezevbvVT9cwDR06NPAYOnaXgFmxYkXgMfRyK/oYup7PbXPrAIuLiw3g0mNm+/btVtvMmTMlXrx4scQTJkyw+rnbCQJJcOue9d+NUaNGWW3vvvuuxPpvhnvdzVXdnsYdPgAAAM8x4QMAAPBcu70//sorr0j84IMPWm033nijxDqFQEq3cAUtx6Jv1bvLi+jb8zqV6qYsdZtLp3ibm5sldm/v79y5U2KdInVTC276NOiz9Dlt2rTJ6vf6669L3LNnT6vtRz/6kcT65w/7t3HT2GvWrAk8R7RfelkitywiaLmViy66yOqnv8duygxoi7Alf4YNGybxggULrDY9R8j3pYL4xgAAAHiOCR8AAIDn2m1K949//KPE7gbyQU8grl692uq31157JXR2iFtr+sdN7epdIdxxoG/P6zToCSecYPULeyJWt+lUsJuq1elefR46dbonQSld90nHW2+9VeKDDjrIatPnGLYrSdjP3KtXr4hnDJ81NDRYr88999xI79Nj9+WXX7baTj75ZInDyhuAdOnrZ11dndWmVzZYuHCh1VZIZQb5fXYAAABoMyZ8AAAAnmPCBwAA4Ll2W8M3b948id0dFrQNGzZI7O42gMLj1ljonSx0HZ0xdm2GW7en6Zo79xi6TR+vtrbW6jd//nyJjznmmEjHc5cA0MfXy7yMHTvW6qeXYnFrCfX7wv67/ndzz4PvCYz56q42N9xwg8SvvfZa4Pv0d+0nP/mJ1bZq1SqJr7nmmraeIpDSunXrrNf674a7S1JYrXO+4Q4fAACA55jwAQAAeK7dpnR1GtdN8+k0AumpwtfS0iKbtbu/T70si3trXi/7oNOWbhpU70LhLhWhU1ff+c53JO7WrZvV7y9/+YvEs2fPlthNJet0bGVlpdVWU1MjsU4RH3vssSZI1B00wpbAcHcaKaQUB9IXVgYQtozQuHHjJHbLAPTrP//5z4HHyPedDFC49HXsgAMOsNr0Na2Q5wTc4QMAAPAcEz4AAADPMeEDAADwXLup4XPrjDS35ujpp5+WeNKkSYmdE7KjqKhItgxzlzkJqlkzxq5V0rF7DL0dmdt2/PHHS6zrBTdt2mT1GzZsmMRvvvmmxNXV1Va/888/X+K33nrLarv22mslbmxslHjKlClWP10X6Nbm6e+CXpJowYIFVr9/+qd/ktitgdX/HvCPuwWh/v3r79DGjRutfpdcconE7pjU12e9JVtZWZnVjxo+JOWLL76QOKwOWV/HjTHmvvvuk/jGG2+M/8RixB0+AAAAzzHhAwAA8Fy7Sen2798/cl93FwQUtpaWFknJhu1O4aYm9WudcnLToDqN667QXl5envJ9/fr1s/qNGTNGYp0uffDBB61+L7zwgsQXX3yx1TZw4ECJ9RItRx11lNVPf7buZ4wxffr0kVj/XIcffrjVTy9NcOKJJ1ptYctqwD/6O6WX+dHLCxnz1TSupssMevToEePZfTU9537PAWOMefbZZzN6X76ncTVGPgAAgOeY8AEAAHjO65Tuli1bJF6/fn0OzwS5VFRU9JUnC1uFpXf0DgL6KV13NwF9DL0ThjH2GNSp1NadP1r17t1bYv2U+NixY61+OsX7hz/8IfCzrrrqKondzb71v0Xfvn2tNp3+GjBggMT19fVWP53Ge/311602/e8G/+lyh1NPPVXisN1ZXCeffHKs56SRwkUUd9xxR6R+QX9LCgHfBAAAAM8x4QMAAPAcEz4AAADPeV3Dt3nz5kj9wnbhyCa39smtFUPbucuyhP3udd2eft/8+fOtfkOGDJHY3RlD18jpNl2zZ4y9nIWOr7/+equfXg5FL+VijL27hl4qJayWyl2yQr/WyxO5dYBz586V+JBDDrHaCrnGpVC54zibO1Loz9I7wZx77rmRj3H11VfHek5RlZaWWq+3bt2ak/NA4dDX51zSOysZY8zDDz+8x/dwhw8AAMBzTPgAAAA8511KV6c2hg4dmsMzSR8p3OTpNK0x4Ztk6/Spfl9lZWXgMZYtW2a1LVmyRGKdgnU/Vx9fLyPhruL+q1/9SuJ/+Zd/CTzftWvXmiC6dOD555+32oYPHy7xyJEjJXY3DD/ooIMkDtu9BNmRzRSuS4+hc845R2K3bGHDhg0Su+ebq/Mnhdu+ZXKtyuYyP2GlGlFSuC7u8AEAAHiOCR8AAIDnvEvpTp8+XeKw27W5TIEgd9xb5HrHi27dugX2bW5ulnjlypVWP53idZ9Y1btQfPrppxK742/w4MESn3XWWRIffPDBVr+JEydK7O7qsXHjRon/7//+T+J169ZZ/WpqaiTWm9YbY8zAgQMl1k/bhj3N7La5aXP4bcKECRLrsaBTuK5Onbz704M06F181qxZk7PzeP/99yP169+/f8Jnklrc8xTu8AEAAHiOCR8AAIDnmPABAAB4zrtCCrcmKUh5eXnCZ4J80dLSInVl7iP1ukZC1/MZY0xxcbHEelkSXW9njF0j98UXX1hte++9t8R6OZRp06ZZ/R555BGJP/nkE4kvvfRSq5+u79PnZ4xd36fr9Nw6EP2zuDscrF69WmL9b+V+VtjSBG5f+C2TpU1uu+22BM4EhSKXdXua3v2oe/fuEjc0NFj9vvzyy2ydUqK4wwcAAOA5JnwAAACe8y6lq9NmYfQSFvBbUVGRpDXd9GZJSUng+xobGyX+/e9/L7HeIN4Ye8mWESNGWG1nnnmmxBdeeKHE++67r9VvxowZEuslK2644Qarn146Rn+uMcbcc889Es+dO1fimTNnWv300jF6+RZjjBkyZIjEepNw93uld1Fwl2Vhp41khK26n01uOj9syR7toYcektjd+B3Ihc2bN0vspnE1d8muQsUdPgAAAM8x4QMAAPAcEz4AAADPeVfDp7eD0ls8LVq0KBengzwRVO+k64/cWiQ9li6++GKJX3rpJavffvvtJ/G2bdusttmzZ6dsmzRpktVv1KhREq9YsSLlORgTvm1Zjx49JNbLw7g1h3pJjDvvvNNq69y5s8S6hs/dxk3/e4b9uyE+udwOUo/dww8/3GqbNWtWpGPcfPPNElPDh1xwr1XPPPNMyn66ltkYu146jm0Bc1WPyx0+AAAAzzHhAwAA8FzBp3T10hnGBKe89I4HaF92794tu0u4y7CE7Rih2/QuHAcffLDVT4+txYsXW206LbphwwaJzz77bKufTqXqfnq5FmOMufzyyyUOWypAp6D18Ywx5pJLLpHY3RVDL6nSp08fid1UtU5ruP+G+meGH8455xyJdZlCOh5//PG4Tic27t8LyhH85i694i5Z1cq9psWRxtWipnDdpbfaeh7c4QMAAPAcEz4AAADPFXxKt7S0NLBN3zZlQ/f2q0OHDpLKdZ+O0iUBYWNk7dq1Eu+zzz5Wm07jhpUO6M92n3rV47hXr14S33TTTVa/MWPGSHzEEUcEHl+nZvWuGMYYU1FRIbGb0tLH0G1uKlz3c9MTbhoChUn/jn/3u99JrMdnGP30ujHGjB8/Pp4TixEp3Pala9euga9by36MMWbJkiVWP30tTHrM6O9dWMlRJrjDBwAA4DkmfAAAAJ5jwgcAAOC5gqzh0/VJbk2W5tYuoX3avXu31Oq5tWi6NsMdS1u3bpVYv8+tUdN1gLW1tVbb8uXLJdbLubh1ULoOrrq6WmK35qSysjLle1z653If5dfnr79Lxhizc+dOifVSMTpOdUzN/TdGbgX9Tl3u+Ndj98ADD0z7c//whz9Yr3NVL+eO8bjrolA43JplvdyWlqudMNzPcsduWzHyAQAAPMeEDwAAwHMFmdLVqVo3TaDTVe6uB2if9LIsLr1bRV1dndWml07RO0106dLF6jd8+HCJ3V0t9BIu+rPclKhOH7/22msS19fXW/322muvFD/F3+lUgP6ssLStmzLWS9Po46WTBstm+gN7FpbGDdOvXz+J3Z1Wgpx77rkSH3rooRl9btxI4bZvOj07bdq0wDbNnVfMnTtX4sMOOyzGswsXdxkE3wQAAADPMeEDAADwHBM+AAAAzxVkDZ/eoueJJ56w2nR9UtjSEWg/WlpapLbTHRO6vsddKmXHjh0S65o491F+XSP1+eefW23jxo1LeQy3dkSfl94+bfbs2VY/XR+Xaa2crkHUP2NYv3S4Sx8g+/Q2UW6dZhC31vPNN99M+3OffPLJtN+TT8KW+UJh0tfJ0047zWobPHiwxHr7TPfaN3LkyITOLru4wwcAAOA5JnwAAACeK8ic53vvvSexm5LSKV3AmL+PidWrVxtj7Fv4xoSnRXWaVad63PfopUyOPvpoq6179+4S65SZewz9Wi8nlE5KV5+jjt3vRFipw9133y3xbbfdlvLcjbGXCwj7WZAbUdO4mrsEhB4Lmvv79WnZE8au38rKyqzXK1eulLhHjx4Sb9y40eqX9LjQ19ckv0/+fFMBAACQEhM+AAAAzxVkSnf+/PmBbTfffLPEEydOzMbpIM917tzZDBw4MGWbTn22pn1b6feEpWNramok7tu3b+Dxdcos7GnAO++8U2KdcjDG3mXGPQ99fJ0WcFN1Qf2MMeb222/f47m7n83m9H764IMPUv73U0891Xqtn+YlJYpCondCWrhwocRh1+ckxni2rplcmQEAADzHhA8AAMBzTPgAAAA8l0gN36uvvmq9Pumkk5L4mJSo24OrqKhIatDcejO9a0ZFRYXVpneM0DUW7rImQbV+qV632rx5s/W6oaFB4vvvv1/iCy64wOpXWloqsbvcyrJlyyQeMmRI4Gf16dNHYrceRf976J/T/Sy9u4i7s4Zb74fkuWO3trY20vv071X/To0Jrit6+eWX0zw7ID8tWbIk16eQVdzhAwAA8BwTPgAAAM8lktLNZgoXaIuSkhKJw9K9eucC95F9vduLmwbTbc3NzRLX19db/QYMGCCxXpZFp3CNsVNw7gbfOo2r+/Xs2TPwGO7P0tjYKLH+t3E/S3NTuEFpbCQnagrX5aZxAWQfO20AAAAgFkz4AAAAPMeEDwAAwHMFubUakCm3PmLjxo0S623L3L56+ZKwGgt3iZJu3bpJrOs0iouLAz9L1+3puj9j7JqrpqYmq03XGerju0uv6NfuMcrLy1P207WI7nmwtVr+0eOQZXJQSHQ9qrvckK/YWg0AAACxYMIHAADguSJ3WYbQzkVFNcaYZXvsiLjt09LS0jfXJ1GoGLc5xdhtA8ZuTjF224CxmzOB4zatCR8AAAAKDyldAAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPMeEDAADwHBM+AAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPMeEDAADwHBM+AAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPdUqnc0VFRUtVVVVCp4Ig1dXVpra2tijX51GoGLe5M3v27NqWlpa+uT6PQpX02G1paZG4qIhLjMbYbRuuu7kRNl9Ia8JXVVVlZs2aFc9ZxURfsIzx86I1evToXJ9CQcvHceuTXbt2Wa87duwocVFR0bJsn49Pkh67O3fulLhz586JfU6mMr2+xzGRZey2Ddfd3AibL6Q14ctUkv8X6eMEDygkeoKH7InjuprkJM+drGlRz7cNk7WM3ofc465zcqjhAwAA8BwTPgAAAM8x4QMAAPBcVmr4cpWH37Jli8Q9e/bMyTkAQBLyvb7JPb+wmr6o9ANC1I76iflCcrjDBwAA4DkmfAAAAJ7LSko3V+K+Latv+RpjTNeuXSUuLi6O9bMAwJh/pELdVNfmzZsldq91maTFkl7zLurxNm3aJHGPHj2stqTTuHGknVGY4p4v3HjjjdbrH/zgBxIfccQRsX5WVNzhAwAA8BwTPgAAAM8x4QMAAPBcIjV82dzfNuyzdu/eHfi+++67T2I31x50vr4+qg3/sD2RP4J+f+Xl5Wkfy71e1tTUSNyvX7+0j2dM/ONL/1zusWfOnCnxkUce2ebzaG5utl536uR1WTtC6O/G9u3brTb9tz+sll+79957Yzy7eHCHDwAAwHNM+AAAADyXyP3rOG7xu+lYfcyg2Bj7tqy+DTt69Gir32effSbxddddZ7XlyxIrrcsu6NXlgSD19fUS69TXt771Latfhw4dUsbIT63XwiR+V1HTuJmUCLjpUr2kSth1u7GxUeIVK1ZY/V555RWJDzjgAKtNL+EStiOH/mxSuGh1yCGHSLxw4UKrbefOnRLfcMMNVtu//du/JXtiEYWVsLXiag8AAOA5JnwAAACey6v72WGbF0ddAV0/XXPSSSdJPG3aNKufvs3fuXPntM4zW1r/DdgkvHAl+bSsm+o/7rjjJJ4zZ47EI0eOtPrNmDFD4i5dusR6TohflFRu2GoFixYtknj48OGRjxF0vLDU0Y4dOyQOS6WGffb69eslvuyyy6x+H330kcSTJ08ObNNPTvbv39/qx/UUqbz66qsSDx48OLDfxIkTs3E6aYtyneAOHwAAgOeY8AEAAHiOCR8AAIDn8qqGT9ftRd2tw61j0ssM6Men3Rq+srIyiWtrawOPkUvskFB43HGrX+vaJ3e5CT3munXrFnh8fYySkpLANh27tR3z58+X+NBDDw38LPghrG5PC1sqJWgcG2PMzTffLPH9998vcV1dndUvrFZaH1+Pa3fsNjU1SXz66adbbfpvgf4+ucdgFxq0evjhhyW+8sorA/vpMfm///u/Vts3v/nN+E8sIdzhAwAA8BwTPgAAAM/lVUpXi3qr3X3EXm8GrlfAdjc41umGPn36ZHKKgDHGmIaGBondZU70GBw/frzEelcAY8LTuFrr7ivGGFNdXW217bPPPhIvXrxYYnfs50vJAuLjXi+DUvru7hdh6c2gVK2bIr3vvvsk1jsS6LKZPdGfrb8b06dPD3zPX//6V+v1U089JfEdd9wR6bPQvl1zzTUSn3XWWYH99O4vRx99dKLnlCTu8AEAAHiOCR8AAIDnmPABAAB4Lus1fEk/El9cXCzxhg0bJHaXb9E1LvX19VZbeXl57OcFf+kaOV3rZIy9NJCun8p0S7PevXtL/Otf/9pq02P6Zz/7mcSPP/641a9Tp7wt3UVMdJ2dvua610G9VMr7779vtd19990pjxG2zIkeW1GX1nKP+cILLwR+lj6Gu8yL/my9xaa7fBHQSj8D8Kc//SnSe2bPnm29/vrXvx7rOSWJO3wAAACeY8IHAADguYxzO+ncrs+kXxz0Y9b33nuv1aZTBd27d8/aOaFwBJUfhO2moVO47vsyTeNqOiWn01bGGDN69GiJ9c4ycXwuCotezuSYY46R2F3G6oEHHpD4/PPPj3TsqNf+dK71+pijRo2SWO++ZIxdfuPuEnP99ddLrNO927Zts/pxvUcrXQbjljsEKeTdibjDBwAA4DkmfAAAAJ7LOKVbCKuVf/vb3w5s0ykEN80BGBM9VZXNp15PO+00iWfMmGG16SfUdRo30/ILFA73d3zsscdKrNNWTU1NVr8rrrgiZT9j7HEdtHNHXPR5HXbYYSn/uzF2OvZf//VfrTZ9jrW1tRKH7SzDd6N9079vd/wHKeRVDrjDBwAA4DkmfAAAAJ5jwgcAAOC5rCej9aPPYauoxyFqTj6JmpRMuI+FU1uYW3V1dRL36NFD4lz+nnRtljtu9RIbeimKbt26xX4eSe+Yg/S4v4Pjjz9e4jfeeEPi008/3er32GOPSezWJpWVlUmc9DXyoIMOkljX7emdZYwx5rjjjpO4srLSaistLU0Zu+fe0NAgsbtES9S/GciOpK8zbg1nFPlyvcuk/jQ/ZjoAAABIDBM+AAAAz2U9pZt0+uuvf/2rxHqV9s2bN1v9MrmVG4ew27CkcPOLTuNq2Rw7+++/v/X6iy++kPill16y2gYNGiRx0hvG50taA6m9+eabEldXV0u8bNkyq5++5ixfvtxq0+NJ/77dkgadMg3rp783btuKFStSntOzzz5r9auqqpLYLVWIuhRL2E4b+VLeg79L+jpz6qmnJnr8tnJLDIK+a1ExugEAADzHhA8AAMBzsaV09a3GXD7ppFNgbopCu+eee7JxOl8Rdhs27PYtckuno5JeaV2nqhobGwP7nXPOOdZrndLiKVq00uUs+ultY4yZN2+exOPGjbPapk+fLvHYsWMl1iliY4wZMWKExNu3b5f4sssus/pdffXVEt9+++1Wm94lRo/5xx9/3Or3X//1XxK710f9VHFzc7PEbvpY70LDdyM39DVU/66yraamJlK/p59+OuEzSS3uOQAzCgAAAM8x4QMAAPAcEz4AAADPxVaMlC8rlPfp00diXTPyyCOPWP1+8IMftPmz4q6TomYvf2X6+w0aI25dkf7+7NixI9KxjzzySOv14sWLJd5vv/0kzrTmkDrA/ND6e0jnd6B/d8OHD5fYrdN75ZVXJD7iiCOstvLycolffPFFifXOHcYY85//+Z8pP/eTTz6x+h111FESn3LKKVab3v1C19i5dYB6yRZ3GStdC6ZrFd3llfS/Yya7FaDtclm3p02ZMkXiCRMmSDxr1iyr349+9KOsnVOSmGEAAAB4jgkfAACA57K+00bS9C35yZMnB/YbOnRorJ8VRqfrSNsWpkx/h0FjxD1GfX29xMOGDZNY76xhjDHf//73JX7iiSesNl3OEMduIKS38kNbfw+XXHKJxHqcGWPM22+/LfEDDzxgtelr5MiRIyX+4Q9/aPXT3w2dStUpMmOMmTRpksTuLhk61fzxxx+n/Fxj7CVbdOrXGGM6d+4ssV6iJezfjzHevuk5gpvG1ZJeiktLspSG2QcAAIDnmPABAAB4jgkfAACA5xJJTOfyUXe9vZRe+mLw4MFWP70FUElJSUaf1dTUJLG7RIDO+VO3V/ji/h263wm9BEb//v0lnjlzptXvmWeekdhdbkILqzmkbqkwpXNdXbp0qcRPPfWUxCeccILV7+KLL5b4uuuus9p0Dd7o0aMlDqtn2rp1q8R6OzZjjJk9e7bEAwcOtNp+/vOfS/zNb35T4j/+8Y9Wv/Hjx0vs1vAF1a2yZSVaucth/fa3v03Zzx0jO3fulFjXiqYjrK5af5eTvD4z8gEAADzHhA8AAMBziaR0c5kyOvnkk1P+d3dl70zSuDpdYYwx3bt3lzjqz+zuouCmJdA+6XFx9tlnS+yOD51mc1MLOmXglhig8IVdY9x0kV72RI+Ff/7nf7b6nXjiiRLrMhdjMtsNQae+zjrrLKutoqJC4n//93+32ubNmydxdXW1xPoaa4z9PXHPT6eaKVtAKkuWLLFe6/GqufODTNK4YeMzqrjL47jDBwAA4DkmfAAAAJ7zbqeNt956S+J+/fpJfNddd2V0PH1LtbS0NLAt7AmclStXSjxo0KCMzgN+mTNnjvX64IMPlljvjJBOGmDTpk0S650GMn2qDIXDTfVUVlZKrK8/3/72t61+L7/8ssTf/e53rTY99nRa2H3SUbftvffeEi9evDiwn3u93Lhxo8T6id2JEyda/YqLi02QONK4eqcQ+EGPNXeHLf09WbduncRuKUEmu19kujuH3g3HTS23dccP7vABAAB4jgkfAACA55jwAQAAeM67Gj5dJ3LUUUdJ7NaCXHDBBYHHCFr1OqxOL+wYuq4FhSmTGg5j7Efz9ert7s4vWqa1SHq3DnYTaN8aGxsl1kv76OVP3Nf77bdf4DGGDRsmsa4PdemxG7Y0kDvGdf3gQQcdlNExwnaXiUovZwM/hI1JXY+q22pqagKPkTT9/cpkaaQw/FUAAADwHBM+AAAAz3mX0t28ebPEH330kcSHHnqo1U8vR3DsscdabWGb0mus5t5+ZPq71o/RL1iwQOLhw4db/XQKinGFttLLl+hleXr16mX1e/311yX+8MMPrbZ9991XYp0uDZPpEkB6l48hQ4YE9mtqGiai3gAAA/5JREFUapK4a9euVhvfG+yJW5alyxZ0etddDmXy5MkSX3nllQmd3Ve1dRkWF3f4AAAAPMeEDwAAwHNM+AAAADznXQ2fXgJlzZo1EuslWoyxt/353ve+F3i8l156SeJx48ZZbXqrNbc2gHqSwpfJMg/uONi5c6fE+rF/XYtkzFe38skES7G0X+6408s5hC0pdO2110r8xBNPWG1TpkyR+M4775TYHauZ1O25y01EPYZbW9VW7nnEXTOF/OKO/9raWomXLFki8emnn271O/PMM9P+rHycE/AXAgAAwHNM+AAAADyXlfvXme5SkIm6ujqJ6+vrJZ46darVT9++dVNh+lHt73//+xJv27Yt8HPdn0unCjJNE0RdCgHJyCRF6t7GX7VqlcR33HGHxL/5zW8yPq90z8NNH8edFkOyWn+XYddOt00vy6Lp66MxdlmKW9oyc+ZMiVevXi3xoEGD9nDGexZ2TdRLtOhruDF2OlnvIGKM/W8Q9btLCrd9W7FihcS9e/eW+PPPP7f6ZTJvSec92ZojcYcPAADAc0z4AAAAPJfI/Wy9o4AxxowYMSKJj0lJ3w4dOHCgxAMGDLD66V04XEEpr3Q21o6aKgi7lctTl4UhaANuY+xdA5566imJFy5cGNjP3UEgyPz5863XBxxwgMRVVVUSL1u2LNLx4D831avHyaJFi6w2/ZSuTq3G8fSh+3SsLl/R6WP3uq3PPx+eekTbuSUnUa9/cRg6dKjE7rVbC7vGxyFbY5kZBQAAgOeY8AEAAHiOCR8AAIDn0q7hc+s3WukcdDZr9lw9evRI+d/dergrrrgiG6ezR9Sh5A93jERdFidqTYc+vq63y9SBBx5ovdbLZejlBlDYolwj9FJSxgTXIeudX4wxZvny5YHHXLt2rcT9+vWTWC+bEvZZ6fjVr34l8S233CLx1q1brX5x13e533HqprMvmzV7rqjX7iTq9nKB0Q0AAOA5JnwAAACeSzulSwoymmzuLoJ4FPrOJitXrsz1KSBHwtKqekkJvbPGnvTv319ifT0L+yz9HQorkXCXrdK70OjP6tWrV+BnxbE8DClctCeMdgAAAM8x4QMAAPAcEz4AAADPJbK1mquhoUHi7t27Z+Mjv8JdSsDdYihu1O0BSJLe7qysrCywXxxLSkS9noXVxEWtl4ta/8w11k9z5syReNSoUTk8E/9whw8AAMBzTPgAAAA8VxS0c0bKzkVFNcaYZcmdDgLs09LS0jfXJ1GoGLc5xdhtA8ZuTjF224CxmzOB4zatCR8AAAAKDyldAAAAzzHhAwAA8BwTPgAAAM8x4QMAAPAcEz4AAADPMeEDAADwHBM+AAAAzzHhAwAA8BwTPgAAAM/9Pzpn52ct4DOlAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 864x576 with 16 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前正在进行 第 18 轮 ....\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_33424/3122445425.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m     \u001b[1;31m# 遍历真实的图像\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 14\u001b[1;33m     \u001b[1;32mfor\u001b[0m \u001b[0mbatch_idx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mbatch_real_data\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0m_\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32min\u001b[0m \u001b[0menumerate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata_loader\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torch\\utils\\data\\dataloader.py\u001b[0m in \u001b[0;36m__next__\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    519\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_sampler_iter\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    520\u001b[0m                 \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_reset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 521\u001b[1;33m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_next_data\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    522\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_num_yielded\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    523\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_dataset_kind\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0m_DatasetKind\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mIterable\u001b[0m \u001b[1;32mand\u001b[0m\u001b[0;31m \u001b[0m\u001b[0;31m\\\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torch\\utils\\data\\dataloader.py\u001b[0m in \u001b[0;36m_next_data\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    559\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_next_data\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    560\u001b[0m         \u001b[0mindex\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_next_index\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# may raise StopIteration\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 561\u001b[1;33m         \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_dataset_fetcher\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfetch\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mindex\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# may raise StopIteration\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    562\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_pin_memory\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    563\u001b[0m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_utils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpin_memory\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpin_memory\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torch\\utils\\data\\_utils\\fetch.py\u001b[0m in \u001b[0;36mfetch\u001b[1;34m(self, possibly_batched_index)\u001b[0m\n\u001b[0;32m     47\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mfetch\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpossibly_batched_index\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     48\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mauto_collation\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 49\u001b[1;33m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdataset\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0midx\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0midx\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mpossibly_batched_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     50\u001b[0m         \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     51\u001b[0m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdataset\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mpossibly_batched_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torch\\utils\\data\\_utils\\fetch.py\u001b[0m in \u001b[0;36m<listcomp>\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m     47\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mfetch\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpossibly_batched_index\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     48\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mauto_collation\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 49\u001b[1;33m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdataset\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0midx\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0midx\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mpossibly_batched_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     50\u001b[0m         \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     51\u001b[0m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdataset\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mpossibly_batched_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torchvision\\datasets\\mnist.py\u001b[0m in \u001b[0;36m__getitem__\u001b[1;34m(self, index)\u001b[0m\n\u001b[0;32m    132\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    133\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtransform\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 134\u001b[1;33m             \u001b[0mimg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtransform\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    135\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    136\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtarget_transform\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torchvision\\transforms\\transforms.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, img)\u001b[0m\n\u001b[0;32m     59\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mimg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     60\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtransforms\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 61\u001b[1;33m             \u001b[0mimg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     62\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mimg\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     63\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torchvision\\transforms\\transforms.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, pic)\u001b[0m\n\u001b[0;32m     96\u001b[0m             \u001b[0mTensor\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mConverted\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     97\u001b[0m         \"\"\"\n\u001b[1;32m---> 98\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mF\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_tensor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpic\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     99\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    100\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__repr__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torchvision\\transforms\\functional.py\u001b[0m in \u001b[0;36mto_tensor\u001b[1;34m(pic)\u001b[0m\n\u001b[0;32m    146\u001b[0m     \u001b[0mimg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mview\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpic\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msize\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpic\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msize\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpic\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetbands\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    147\u001b[0m     \u001b[1;31m# put it from HWC to CHW format\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 148\u001b[1;33m     \u001b[0mimg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpermute\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontiguous\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    149\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimg\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mByteTensor\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    150\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mimg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdtype\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdefault_float_dtype\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m255\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "\"\"\"\n",
    "    训练过程\n",
    "\"\"\"\n",
    "\n",
    "for epoch in range(1, num_epochs+1):\n",
    "    \n",
    "    print(f\"当前正在进行 第 {epoch} 轮 ....\")\n",
    "    \n",
    "    # 设置训练模式\n",
    "    generator.train()\n",
    "    discriminator.train()\n",
    "    \n",
    "    # 遍历真实的图像\n",
    "    for batch_idx, (batch_real_data, _) in enumerate(data_loader):\n",
    "        \n",
    "               \n",
    "        # 1, 先训练鉴别器\n",
    "        \n",
    "        # 1.1 准备数据\n",
    "        # 图像转向量 [b, 1, 28, 28] ---> [b, 784]\n",
    "        real_data = batch_real_data.view(batch_real_data.size(0), -1).to(device=device)\n",
    "        noise = get_noise(real_data.size(0))\n",
    "        fake_data = generator(noise).detach()\n",
    "        \n",
    "        # 1.2 训练过程\n",
    "        \n",
    "        # 鉴别器的优化器梯度情况\n",
    "        d_optimizer.zero_grad()\n",
    "        \n",
    "        # 对真实数据鉴别\n",
    "        real_pred = discriminator(real_data)\n",
    "        \n",
    "        # 计算真实数据的误差\n",
    "        real_loss = loss_fn(real_pred, get_real_data_labels(real_data.size(0)))\n",
    "        \n",
    "        # 真实数据的梯度回传\n",
    "        real_loss.backward()\n",
    "        \n",
    "        # 对假数据鉴别\n",
    "        fake_pred = discriminator(fake_data)\n",
    "        \n",
    "        # 计算假数据的误差\n",
    "        fake_loss = loss_fn(fake_pred, get_fake_data_labels(fake_data.size(0)))\n",
    "        \n",
    "        # 假数据梯度回传\n",
    "        fake_loss.backward()\n",
    "        \n",
    "        # 梯度更新\n",
    "        d_optimizer.step()\n",
    "        \n",
    "#         print(f\"鉴别器的损失:{real_loss + fake_loss}\")\n",
    "        \n",
    "        \n",
    "        # 2, 再训练生成器\n",
    "        \n",
    "        # 获取生成器的生成结果\n",
    "        fake_pred = generator(get_noise(real_data.size(0)))\n",
    "        \n",
    "        # 生产器梯度清空\n",
    "        g_optimizer.zero_grad()\n",
    "        \n",
    "        # 把假数据让鉴别器鉴别一下\n",
    "        d_pred = discriminator(fake_pred)\n",
    "        \n",
    "        # 计算损失\n",
    "        g_loss = loss_fn(d_pred, get_real_data_labels(d_pred.size(0)))\n",
    "        \n",
    "        # 梯度回传\n",
    "        g_loss.backward()\n",
    "        \n",
    "        # 参数更新\n",
    "        g_optimizer.step()\n",
    "        \n",
    "#         print(f\"生成器误差：{g_loss}\")\n",
    "   \n",
    "\n",
    "    #  每训练一轮，查看生成器的效果\n",
    "    generator.eval()\n",
    "    \n",
    "    with torch.no_grad():\n",
    "        \n",
    "        # 正向推理\n",
    "        img_pred = generator(test_noise)\n",
    "        img_pred = img_pred.view(img_pred.size(0), 28, 28).cpu().data\n",
    "        \n",
    "        # 画图\n",
    "        display.clear_output(wait=True)\n",
    "        \n",
    "        # 设置画图的大小\n",
    "        fig = plt.figure(1, figsize=(12, 8)) \n",
    "        # 划分为 4 x 4 的 网格\n",
    "        gs = gridspec.GridSpec(4, 4)\n",
    "        \n",
    "        # 遍历每一个\n",
    "        for i in range(4):\n",
    "            for j in range(4):\n",
    "                # 取每一个图\n",
    "                X = img_pred[i * 4 + j, :, :]\n",
    "                # 添加一个对应网格内的子图\n",
    "                ax = fig.add_subplot(gs[i, j])\n",
    "                # 在子图内绘制图像\n",
    "                ax.matshow(X, cmap=plt.get_cmap(\"Greys\"))\n",
    "#                 ax.set_xlabel(f\"{label}\")\n",
    "                ax.set_xticks(())\n",
    "                ax.set_yticks(())\n",
    "        plt.show()\n",
    " "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
